package com.mzx.javase.thread.tongxin;

/**
 * 类描述：
 * 模拟两个线程，一个顾客线程，一个老板线程
 * 顾客对老板说，我要包子、馒头
 * 老板线程去给顾客相应的东西
 *
 * 如何使用wait和notify方法
 * 1.wait和notify方法都需要在同步代码块中执行synchronized(同一个锁对象){要执行的代码片段}
 * 2.调用锁对象的wait和notify方法进行线程等待/线程通知
 *
 * 需要注意：
 * 1.哪怕只通知了一个等待线程，被通知的线程也不能立即恢复执行，而是等待同步代码块重新竞争并拥有锁之后，再从wait方法中断的地方往下继续执行
 * 总结如下：
 * 如果能获取锁，线程就会从wait方法中断的地方继续向下执行
 * 否则，从wait set出来的线程会进入到entry set，线程就从WATING状态又变回BLOCKED状态
 *
 * 调用wait和notify方法需要注意的细节：
 * 1. wait方法与notify方法必须要由同一个锁对象调用。因为：对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
 * 2. wait方法与notify方法是属于Object类的方法的。因为：锁对象可以是任意对象，而任意对象的所属类都是继承了Object类的。
 * 3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为：必须要通过锁对象调用这2个方法。
 *
 * @ClassName WaitNotifyDemo
 * @Description TODO
 * @Author 马子鑫
 * @Date 2022/8/6 15:30
 * @Version 1.0
 */
public class WaitNotifyDemo {
    public static void main(String[] args) {
        //等待唤醒机制要和同步代码块synchronized一起使用，需要创建一个锁对象
        Object lock = new Object();//这个就是协调者的角色
        new Thread(new Runnable() {
            @Override
            public void run() {
//                System.out.println("1、告诉老板要的早餐产品");
                //进入等待，等老板做好
                synchronized (lock) {
                    System.out.println("1、告诉老板要的早餐产品");
                    try {
                        lock.wait();//使当前线程，顾客线程进入等待
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println("3、拿到老板做好的早餐，开始吃");
                }
                //唤醒之后打印一下，等待之后必须被唤醒才能继续执行
//                System.out.println("3、拿到老板做好的早餐，开始吃");
            }
        }, "顾客线程").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                //老板线程等待两秒时间
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
//                System.out.println("2、老板线程做好了相应的早餐");
                //通知顾客，早餐做好了
                synchronized (lock) {
                    System.out.println("2、老板线程做好了相应的早餐");
                    lock.notify();
                }
            }
        },"老板线程").start();
    }
}
